//
//  main.cpp
//  imageProcess
//
//  Created by s on 2021/4/22.
//

#include <iostream>
#include <opencv2/opencv.hpp>
#include <ctime>


using namespace cv;
using namespace std;

using std::string;

void gammaCorrection(cv::Mat& src, cv::Mat& dst, float fGamma);
void sharpen1(Mat& image);
void sharpen0(Mat& image);
void sharpen2(Mat& image);

void sharpen3(Mat& image);
void reduceBackground(cv::Mat& image);
void reduceBackgroundAlgorithm(cv::Mat& image);
void imageSharp(cv::Mat& image, int amount);
void colorGradation(cv::Mat& image);

void sharpen4(Mat& image);
void sharpen5(Mat& image);
void sharpen6(Mat& image);
void sharpen7(Mat& image);

std::time_t getTimeStamp()
{
    std::chrono::time_point<std::chrono::system_clock,std::chrono::milliseconds> tp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());//获取当前时间点
    std::time_t timestamp =  tp.time_since_epoch().count(); //计算距离1970-1-1,00:00的时间长度
    return timestamp;
}

int main(int argc, const char * argv[]) {
//    string path = "/Users/l/src/mac/image-process/imageProcess/IMG_4938.jpg";
//    string path = "/Users/l/src/mac/image-process/imageProcess/IMG_4894.jpg";
//    string path = "/Users/l/src/mac/image-process/imageProcess/11.jpg";
    string path = "/Users/l/src/mac/image-process/imageProcess/12.png";
//    string path = "/Users/l/src/mac/image-process/imageProcess/13.png";

    Mat originImage = imread(path);

    namedWindow("origin");
    imshow("origin", originImage);
    Mat image = originImage.clone();

    //    sharpen0(image);
    //    sharpen1(image);
    //    sharpen2(image);
    //    sharpen3(image);
    //    sharpen4(image);
    //    sharpen5(image);
    //    sharpen6(image);
    sharpen7(image);

    namedWindow("result");
    imshow("result", image);
    waitKey(0);
    return 0;
}


void filteredGrey(Mat &image){
    Mat hsvImage;
    cvtColor(image, hsvImage, COLOR_BGR2HSV);
    double H = 0.0, S = 0.0, V = 0.0;
    for(int i = 0; i < hsvImage.rows; i++)
    {
        for(int j = 0; j < hsvImage.cols; j++)
        {
            H = hsvImage.at<Vec3b>(i,j)[0];
            S = hsvImage.at<Vec3b>(i,j)[1];
            V = hsvImage.at<Vec3b>(i,j)[2];

            if(((S >= 0 && S <= 55) && (H >= 0 && H <= 180) && (V >= 120 && V <= 255)))
            {
                image.at<Vec3b>(i, j)[0] = 255;//image.at<Vec3b>(i, j)[0];
                image.at<Vec3b>(i, j)[1] = 255;//image.at<Vec3b>(i, j)[1];
                image.at<Vec3b>(i, j)[2] = 255;//image.at<Vec3b>(i, j)[2];
            }
        }
    }
}

void sharpen7(Mat& image) {
    // 基于当前系统的当前日期/时间
    time_t now = getTimeStamp();

    cout << "毫秒数:" << now << endl;

    cv::Mat kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0,
                      -1, 5, -1,
                      0, -1, 0);
    filter2D(image, image, image.depth(), kernel);

    time_t now1 = getTimeStamp();
    cout << "经过1:" << now1 - now << endl;

//        cv::Mat black = Mat(image.rows, image.cols, CV_8UC3, Scalar(0, 0, 0));
//        double alpha = 1;
//        cv::addWeighted(image, alpha, black, 1 - alpha, 10, image);

    cv::Mat e1 = getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2)); //定义结构元素
    erode(image, image, e1);
//    dilate(image, image, e1);
    time_t now2 = getTimeStamp();
    cout << "经过2:" << now2 - now1 << endl;

    filteredGrey(image);

    time_t now3 = getTimeStamp();
    cout << "经过3:" << now3 - now2 << endl;
    cout << "经过total:" << now3 - now << endl;

    //    cv::Mat cw = Mat(image.rows, image.cols, CV_8UC3, Scalar(0, 0, 0));
    //    double alpha1 = 0.8;
    //    cv::addWeighted(image, alpha1, cw, 1 - alpha1, 0, image);

    //    cv::Mat e = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); //定义结构元素
    //    erode(image, image, e);

    //    int height = image.rows;
    //    int width = image.cols;
    //    uchar r, g, b;
    //    int threshold = 150;
    //    float scale = 0.05;
    //    for (int i = 0; i < height; i++)
    //    for (int j = 0; j < width; j++)
    //    {
    //        r = image.at<cv::Vec4b>(i, j)[2];
    //        g = image.at<cv::Vec4b>(i, j)[1];
    //        b = image.at<cv::Vec4b>(i, j)[0];
    //
    //        if (r > threshold && b > threshold && g > threshold)
    //        {
    //            image.at<cv::Vec4b>(i, j)[2] = 255;
    //            image.at<cv::Vec4b>(i, j)[1] = 255;
    //            image.at<cv::Vec4b>(i, j)[0] = 255;
    //        } else {
    //            image.at<cv::Vec4b>(i, j)[2] = r * (1 -  scale);
    //            image.at<cv::Vec4b>(i, j)[1] = g * (1 - scale);
    //            image.at<cv::Vec4b>(i, j)[0] = b * (1 - scale);
    //        }
    //    }
    //    cv::Mat e = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); //定义结构元素
    //    erode(image, image, e);
    //    dilate(image, image, e);

    //    cv::Mat kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0,
    //                      -1, 5, -1,
    //                      0, -1, 0);
    //    filter2D(image, image, image.depth(), kernel);
}

void sharpen6(Mat& image) {
    Mat hsv = image.clone();
    Mat hsvt = image.clone();
    
    cv::cvtColor(image, hsv, COLOR_BGR2HSV);

    double low_H = 0;
    double high_H = 180;

    double low_S = 0;
    double high_S = 70;

    double low_V = 125;
    double high_V = 255;
    cv::inRange(hsv, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), image);

    //    cv::cvtColor(image, image, COLOR_HSV2BGR);
}

/// 通过过滤分个像素点的值来处理
void sharpen5(Mat& image) {
    cv::Mat kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0,
                      -1, 5, -1,
                      0, -1, 0);
    filter2D(image, image, image.depth(), kernel);

    int height = image.rows;
    int width = image.cols;
    uchar r, g, b;
    int threshold = 100;
    float scale = 0.9;
    for (int i = 0; i < height; i++)
    for (int j = 0; j < width; j++)
    {
        r = image.at<cv::Vec4b>(i, j)[2] * scale;
        g = image.at<cv::Vec4b>(i, j)[1] * scale;
        b = image.at<cv::Vec4b>(i, j)[0] * scale;

        if (r > threshold && b > threshold && g > threshold)
        {
            image.at<cv::Vec4b>(i, j)[2] = 255;
            image.at<cv::Vec4b>(i, j)[1] = 255;
            image.at<cv::Vec4b>(i, j)[0] = 255;
        }
    }

    cv::Mat e = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); //定义结构元素
    dilate(image, image, e);
    erode(image, image, e);
}

// 灰度图处理
void sharpen4(Mat& image) {

    Mat originImage = image.clone();
    //1.将图像转为灰度图
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    //    CvUtils::SetShowWindow(gray, "gray", 0, 30);
    imshow("gray", gray);


    //定义腐蚀和膨胀的结构化元素和迭代次数
    Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
    int iteration = 9;


    //2.将灰度图进行膨胀操作
    Mat dilateMat;
    dilate(gray, dilateMat, element, Point(-1, -1), iteration);
    //    morphologyEx(gray, dilateMat, MORPH_DILATE, element, Point(-1, -1), iteration);
    //    imshow("dilate", dilateMat);


    //3.将膨胀后的图再进行腐蚀
    Mat erodeMat;
    erode(dilateMat, erodeMat, element, cv::Point(-1, -1), iteration);
    //    morphologyEx(dilateMat, erodeMat, MORPH_ERODE, element, cv::Point(-1, -1), iteration);
    //    imshow("erode", erodeMat);

    //4.膨胀再腐蚀后的图减去原灰度图再进行取反操作
    Mat calcMat = ~(erodeMat - gray);
    //    CvUtils::SetShowWindow(calcMat, "calc", gray.cols*2, 30);
    //    imshow("calc", calcMat);


    //5.使用规一化将原来背景白色的改了和原来灰度图差不多的灰色
    //    Mat removeShadowMat;
    normalize(calcMat, image, 0, 255, NORM_MINMAX);
    //    CvUtils::SetShowWindow(removeShadowMat, "dst",
    //      gray.cols, 30);

}

// 灰度图像
void sharpen3(Mat& image) {
    reduceBackground(image);
}

void reduceBackground(cv::Mat& image) {
    cvtColor(image, image, cv::COLOR_BGR2GRAY);
    image.convertTo(image, CV_32FC1, 1.0 / 255);
    reduceBackgroundAlgorithm(image);
    cv::GaussianBlur(image, image, cv::Size(3, 3), 0, 0, 4);
    colorGradation(image);
}

void reduceBackgroundAlgorithm(cv::Mat& image) {
    cv::Mat gauss;
    cv::blur(image, gauss, cv::Size(101, 101));
    cv::divide(image, gauss, image);
    imageSharp(image, 101);
    image.convertTo(image, CV_8UC1, 255);
}

void imageSharp(cv::Mat& image, int amount) {
    double sigma = 3;
    cv::Mat gauss;
    cv::Mat sub;
    cv::GaussianBlur(image, gauss, cv::Size(7, 7), sigma, sigma, 4);
    cv::subtract(image, gauss, sub);
    cv::addWeighted(image, 1, sub, amount / 100, 0, image);
}

void colorGradation(cv::Mat& image) {
    int highLight = 255;
    int shadow = 120;
    int diff = highLight - shadow;

    image.convertTo(image, CV_32FC1);
    cv::Mat rDiff;
    cv::subtract(image, cv::Scalar(shadow), rDiff);
    cv::Mat temp;
    rDiff.convertTo(temp, CV_32FC1, 255.0 / diff);
    temp.convertTo(image, CV_8UC1);
}

void sharpen2(Mat& image) {
    // x 增加亮度
    image.convertTo(image, image.depth(), 1, 10);
}

void sharpen0(Mat& image) {
    cv::Mat kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0,
                      -1, 5, -1,
                      0, -1, 0);
    filter2D(image, image, image.depth(), kernel);
}

void sharpen1(cv::Mat& image) {

    // 划分算法
    //如果混合色与基色相同则结果色为白色
    //如混合色为白色则结果色为基色不变
    //如混合色为黑色则结果色为白色
    cv::Mat src = image.clone();
    src.convertTo(src, CV_32FC3, 1.0 / 255);
    cv::Mat gauss;
    cv::Mat dst = src.clone();
    cv::GaussianBlur(src, gauss, cv::Size(101, 101), 0);
    dst = src / gauss;
    dst.convertTo(image, CV_8UC3, 255);
    //     gamma变换
    cv::Mat matGamma;
    gammaCorrection(dst, image, 1);
}

//Gamma校正 fGamaa=0.45是常用值
void gammaCorrection(cv::Mat& src, cv::Mat& dst, float fGamma) {
    //    CV_Assert(src.data);
    // accept only char type matrices
    //    CV_Assert(src.depth() != sizeof(uchar));
    // build look up table
    unsigned char lut[256];
    for (int i = 0; i < 256; i++) {
        lut[i] = cv::saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
    }

    dst = src.clone();
    const int channels = dst.channels();
    switch (channels) {
        case 1: {
            cv::MatIterator_<uchar> it, end;
            for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++)
            *it = lut[(*it)];
            break;
        }
        case 3: {
            cv::MatIterator_<cv::Vec3b> it, end;
            for (it = dst.begin<cv::Vec3b>(), end = dst.end<cv::Vec3b>(); it != end; it++) {
                (*it)[0] = lut[((*it)[0])];
                (*it)[1] = lut[((*it)[1])];
                (*it)[2] = lut[((*it)[2])];
            }
            break;
        }
    }
}
